require "vagrant/timer/version"
require "fileutils"

require "vagrant"

module Vagrant
    module Timer
        class Plugin < Vagrant.plugin("2")
            name "vagrant-timer"
            description <<-DESC
            A plugin to capture timing information from a vagrant run.
            Set the environment variable VAGRANT_TIMER_LOG to the file to
            log timing data to.

            VAGRANT_TIMER_LOG can have strftime variables in it, which
            will be replaced by the time that the vagrant step started.
            DESC

            action_hook("timer") do |hook|
                hook.prepend(Middleware)
            end
        end

        class Middleware
            @@previous_action_name = nil

            def initialize(app, env)
                @init_time = Time.now.utc

                @app = app
            end

            def call(env)
                @start_call = Time.now.utc
                @app.call(env)
                @end_call = Time.now.utc

                env_obj = env[:env]
                vagrantfile = env_obj && env_obj.vagrantfile
                config = vagrantfile && vagrantfile.config
                vm = config && config.vm
                box = vm && vm.box

                event = {
                    :ruby_version    => RUBY_VERSION,
                    :platform        => RUBY_PLATFORM,
                    :vagrant_version => Vagrant::VERSION,
                    :box             => box,
                    :action_name     => env[:action_name],
                    :initialized_at  => @init_time.to_s,
                    :started_at      => @start_call.to_s,
                    :ended_at        => @end_call.to_s,
                    :init_duration   => @start_call - @init_time,
                    :call_duration   => @end_call - @start_call,
                }

                if !@@previous_action_name.nil?
                    event[:previous_action_name] = @@previous_action_name
                    event[:since_previous_action] = @init_time - @@previous_action_end
                end

                if !ENV['VAGRANT_TIMER_LOG'].nil?
                    log_path = @init_time.strftime(ENV['VAGRANT_TIMER_LOG'])

                    if !File::exist?(File::dirname(log_path))
                        FileUtils.mkdir_p(File::dirname(log_path))
                    end

                    begin
                        File.open(log_path, 'a') do |file|
                            file.write(event.to_json + "\n")
                        end
                    rescue SystemCallError => err
                        puts "Unable to log event to #{ENV['VAGRANT_TIMER_LOG']}: #{err}"
                    end
                end
                @@previous_action_name = env[:action_name]
                @@previous_action_end = @end_call
            end
        end
    end
end
